package com.youjiang.meeting.utils.weixin;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.thoughtworks.xstream.XStream;
import com.youjiang.meeting.utils.weixinbean.Articles;
import com.youjiang.meeting.utils.weixinbean.NewsMessage;

/**
 * <p>
 * Title: WeixinSignUtil
 * </p> 
 * <p>
 * Description:微信签名工具类
 * </p> 
 * <p>
 * Company: YouJiang
 * </p> 
 *
 * @author feng
 * @date 2016年11月22日 下午3:42:31
 * @version 1.0
 */
public class WeixinSignUtil {
	/***
	 * 微信浏览器支付签名
	 * @param httpResult 微信统一下单返回的结果
	 * @param key
	 * @return 公众号id appId <br>
		时间戳 timeStamp<br>
		随机字符串 nonceStr <br>
		订单详情扩展字符串 package <br>
		签名方式 signType <br>
		签名 paySign  <br>
	 * @throws Exception
	 */
	public static Map<String,String> browserPaySign(Map<String,String> httpResult,String key) throws Exception{
		Map<String,String> map=new HashMap<String,String>();
		map.put("appId", httpResult.get("appid"));
		map.put("timeStamp", String.valueOf(new Date().getTime()));
		map.put("nonceStr", httpResult.get("nonce_str"));
		map.put("package","prepay_id="+httpResult.get("prepay_id"));
		map.put("signType", "MD5");
		String sign=FormatBizQueryParaMap(map)+"&key="+key;
		map.put("sign", resultMD5(sign, true));
		return map;
	}
	/***
	 * 微信APP支付
	 * @param httpResult
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public static Map<String,String> appPaySign(Map<String,String> httpResult,String key,String mch_id) throws Exception{
		Map<String,String> map=new HashMap<String,String>();
		map.put("appid", httpResult.get("appid"));
		map.put("partnerid", mch_id);
		map.put("prepayid", httpResult.get("prepay_id"));
		map.put("package", "Sign=WXPay");
		map.put("noncestr", httpResult.get("nonce_str"));
		map.put("timestamp", String.valueOf((new Date().getTime())/1000));
		String sign=FormatBizQueryParaMap(map)+"&key="+key;
		map.put("sign", resultMD5(sign, true));
		return map;
	}
	
	/***
	 * md5加密
	 * @param str 待加密字符串
	 * @param isToUpperCase 是否要转大写
	 * @return
	 */
	public static String resultMD5(String str,boolean isToUpperCase){
		if(isToUpperCase){
			return DigestUtils.md5Hex(str).toUpperCase();
		}else{
			return DigestUtils.md5Hex(str);
		}
	}
	/**
	 * 把map中的数据拼接成为 key字典排序
	 * @param paraMap
	 * @return
	 * @throws Exception
	 */
	public static String FormatBizQueryParaMap(Map<String, String> paraMap) throws Exception {
	    String buff = "";
	    try {
	        List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(
	                paraMap.entrySet());
	        Collections.sort(infoIds,
	                new Comparator<Map.Entry<String, String>>() {
	                    public int compare(Map.Entry<String, String> o1,
	                            Map.Entry<String, String> o2) {
	                        return (o1.getKey()).toString().compareTo(
	                                o2.getKey());
	                    }
	                });
	        for (int i = 0; i < infoIds.size(); i++) {
	            Map.Entry<String, String> item = infoIds.get(i);
	            if (item.getKey() != "") {
	                String key = item.getKey();
	                String val = item.getValue();
	                buff += key + "=" + val + "&";
	            }
	        }
	        if (buff.isEmpty() == false) {
	            buff = buff.substring(0, buff.length() - 1);
	        }
	    } catch (Exception e) {
	    	e.printStackTrace();
	        throw new Exception(e.getMessage());
	    }
	    return buff;
	}
	/****
	 * 把微信返回来的数据转成map
	 * @param in
	 * @return
	 * @throws IOException
	 * @throws DocumentException
	 */
	public static Map<String, String> XMLToMessage(String in) throws IOException, DocumentException{
		Map<String, String> map=new HashMap<String, String>();
		SAXReader sax=new SAXReader();
		Document docu=sax.read(new ByteArrayInputStream(in.getBytes("UTF-8")));
		Element element=docu.getRootElement();
		List<Element> list= element.elements();
		for(Element e:list){
			if(e.elements().size()>0){
				List<Element> li=e.elements();
				for(Element it:li){
					String text=it.getText();
					if(text.indexOf("<![CDATA[")!=-1){
						text=text.substring(text.indexOf("<![CDATA[")+1, text.indexOf("]]>"));
					};
					map.put(it.getName(), it.getText());
				}
			}else{
				map.put(e.getName(), e.getText());
			}
		}
		return map;
	}
	/***
	 * 把参数转成xml格式
	 * @param arr
	 * @return
	 */
	public static String ArrayToXml(Map<String, String> arr) {
        String xml = "<xml>";
        Iterator<Entry<String, String>> iter = arr.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<String, String> entry = iter.next();
            String key = entry.getKey();
            String val = entry.getValue();
            if (IsNumeric(val)) {
                xml += "<" + key + ">" + val + "</" + key + ">";
            } else
                xml += "<" + key + "><![CDATA[" + val + "]]></" + key + ">";
        }
        xml += "</xml>";
        return xml;
    }
	/**
	 * 
	 * @param news
	 * @return
	 */
	public static String articlesToItem(NewsMessage news){
		String xml = "<xml>";
		 	xml=xml+"<ToUserName><![CDATA["+news.getToUserName()+"]]></ToUserName>";
		 	xml=xml+"<FromUserName><![CDATA["+news.getFromUserName()+"]]></FromUserName>";
		 	xml=xml+"<CreateTime>"+news.getCreateTime()+"</CreateTime>";
		 	xml=xml+"<MsgType><![CDATA["+news.getMsgType()+"]]></MsgType>";
		 	xml=xml+"<ArticleCount>"+news.getArticles().size()+"</ArticleCount>";
		 	xml=xml+"<Articles>";
		 	for(Articles it:news.getArticles()){
		 		xml=xml+"<item>";
		 		xml=xml+"<Title><![CDATA["+it.getTitle()+"]]></Title>";
		 		xml=xml+"<Description><![CDATA["+it.getDescription()+"]]></Description>";
		 		xml=xml+"<PicUrl><![CDATA["+it.getPicUrl()+"]]></PicUrl>";
		 		xml=xml+"<Url><![CDATA["+it.getUrl()+"]]></Url>";
		 		xml=xml+"</item>";
		 	}
		 	xml=xml+"</Articles>";
	        xml=xml+ "</xml>";
	        return xml;
		
	}
	
	/***
	 *
	 * @param str
	 * @return
	 */
	public static boolean IsNumeric(String str) {
        if (str.matches("\\d *")) {
            return true;
        } else {
            return false;
        }
    }
    /** 
     * 除去数组中的空值和签名参数
     * @param sArray 签名参数组
     * @return 去掉空值与签名参数后的新签名参数组
     */
    public static Map<String, String> paraFilter(Map<String, String> sArray) {

        Map<String, String> result = new HashMap<String, String>();

        if (sArray == null || sArray.size() <= 0) {
            return result;
        }
        for (String key : sArray.keySet()) {
            String value = sArray.get(key);
            if (value == null || value.equals("")) {
                continue;
            }
            result.put(key, value);
        }

        return result;
    }
  /***
   * 把NewsMessage转成xml的字符串
   * @param message
   * @return
   */
  	public static String newsMessageToXML(NewsMessage message){
  		XStream stream=new XStream();
  		stream.alias("xml", message.getClass());
  		stream.alias("item", Articles.class);
  		return stream.toXML(message);
  	}
    /****
     * 得到真实ip
     * @param request
     * @return
     */
    public static String getIpAddress(HttpServletRequest request) { 
	    String ip = request.getHeader("x-forwarded-for"); 
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
	      ip = request.getHeader("Proxy-Client-IP"); 
	    } 
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
	      ip = request.getHeader("WL-Proxy-Client-IP"); 
	    } 
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
	      ip = request.getHeader("HTTP_CLIENT_IP"); 
	    } 
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
	      ip = request.getHeader("HTTP_X_FORWARDED_FOR"); 
	    } 
	    if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { 
	      ip = request.getRemoteAddr(); 
	    } 
	    return ip; 
	  } 
}
